#pragma once

#include <iostream>
using namespace std;

namespace ys
{
	template<class T>
	struct list_Node
	{
		T _data;
		list_Node* _next;
		list_Node* _prev;

		list_Node(const T& x = T())
			:_data(x)
			, _next(nullptr)
			, _prev(nullptr)
		{}
	};

	template<class T, class Ref, class Ptr>
	struct __list_iterator
	{
		typedef list_Node<T> Node;
		typedef __list_iterator<T, Ref, Ptr> self;
		Node* _node;

		__list_iterator(Node* node)
			:_node(node)
		{}
		bool operator!=(const self& s) const
		{
			return _node != s._node;
		}
		Ref operator*()
		{
			return _node->_data;
		}
		Ptr operator->()
		{
			return &_node->_data;
		}
		self& operator++()
		{
			_node = _node->_next;
			return _node;
		}
		self& operator--()
		{
			_node = _node->_prev;
			return _node;
		}
		self operator++(int)
		{
			self tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		self operator--(int)
		{
			self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
	};

	/*template<class T>
	struct __list_const_iterator
	{
		typedef list_Node<T> Node;
		typedef __list_const_iterator<T> self;
		Node* _node;

		__list_const_iterator(Node* node)
			:_node(node)
		{}
		bool operator!=(const self& s) const
		{
			return _node != s._node;
		}
		const T& operator*()
		{
			return _node->_data;
		}
		const T* operator->()
		{
			return &_node->_data;
		}
		self& operator++()
		{
			_node = _node->_next;
			return _node;
		}
		self& operator--()
		{
			_node = _node->_prev;
			return _node;
		}
		self operator++(int)
		{
			self tmp(*this);
			_node = _node->_next;
			return tmp;
		}
		self operator--(int)
		{
			self tmp(*this);
			_node = _node->_prev;
			return tmp;
		}
	};*/

	template<class T>
	class list
	{
		typedef list_Node<T> Node;
	public:
		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator < T, const T&, const T*> const_iterator;
		//typedef __list_const_iterator<T> const_iterator;

		list()
		{
			empty_init();
		}

		list(const list<T>& ls)
		{
			empty_init();
			for (auto e : ls)
			{
				push_back(e);
			}
		}

		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
		}

		list<T>& operator=(list<T> ls)
		{
			if(this != &ls)
				swap(ls);
			return *this;
		}

		/*list<T>& operator=(const list<T>& ls)
		{
			if (this != &ls)
			{
				clear();
				for (auto e : ls)
				{
					push_back(e);
				}
			}
			return *this;
		}*/

		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
		}
		void push_back(const T& x)
		{
			insert(end(), x);
		}
		void push_front(const T& x)
		{
			insert(begin(), x);
		}
		void pops_front()
		{
			erase(begin());
		}
		void pops_back()
		{
			erase(--end());
		}
		iterator begin()
		{
			return _head->_next;
		}
		const_iterator end() const
		{
			return _head;
		}
		const_iterator begin() const
		{
			return _head->_next;
		}
		iterator end()
		{
			return _head;
		}
		iterator insert(iterator pos, const T& val)
		{
			Node* cur = pos._node;
			Node* newnode = new Node(val);

			Node* prev = cur->_prev;

			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = cur;
			cur->_prev = newnode;

			return iterator(newnode);
		}
		iterator erase(iterator pos)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* next = cur->_next;

			delete cur;
			prev->_next = next;
			next->_prev = prev;

			return iterator(next);
		}

		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				erase(it);
			}
		}

		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}
	private:
		Node* _head;
	};

	void test1()
	{
		list<int> A;
		A.push_back(1);
		A.push_back(2);
		A.push_back(3);
		A.push_back(4);
		A.push_back(5);

		list<int>::iterator it = A.begin();
		while (it != A.end())
		{
			cout << *it << " ";
			it++;
		}
		cout << endl;
	}
}
	/*struct AA
	{
		AA(int a1 = 0, int a2 = 0)
			:_a1(a1)
			,_a2(a2)
		{}
		int _a1;
		int _a2;
	};

	void test2()
	{
		list<AA> lt;
		lt.push_back(AA(1, 1));
		lt.push_back(AA(2, 2));
		lt.push_back(AA(3, 3));
		lt.push_back(AA(4, 4));

		list<AA>::iterator it = lt.begin();
		while (it != lt.end())
		{
			cout << it->_a1 << " " << it->_a2 << endl;
			cout << it.operator->()->_a1 << " " << it.operator->()->_a2 << endl;
		}
	}*/
//	template<typename T>
//	void printf_list(const list<T>& lt)
//	{
//		typename list<T>::iterator it = lt.begin();
//	}
//
//	template <typename Container>
//	void print_ontainer(const Container& con)
//	{
//		typename Container::iterator it = con.begin();
//	}
//}